declare var $: any;

// Type Declaration Space 

class Foo {};
interface Bar {};
type Bas = {};

// Variable Declaration Space : can use as a variable
class Foo1 {};
var s = Foo1;


// Module
export let ss = 2222;
export type s1 = {foo: string};
let s2 = 123;
export { s2 as s3}; // alias

import {s3 as s5 } from './1'
import * as t1 from './1'

export * from './1'
export {s3 as s4} from './1'

import * as fooo from 'foo'  // foo is declared in global.d.ts
fooo.bar

import foo = require("foo") // imports the type information when foo not used in the variable declaration the import is completely removed from generated javascript

foo.bar

// lazy loading
import foo1 = require('foo');
export function loadFoo() {
    // This is lazy loading `foo` and using the original module *only* as a type annotation
    var _foo: typeof foo = require('foo');
    // Now use `_foo` as a variable instead of `foo`.
}


// ensure import load a file just for the side effect
import fo0o1 = require('foo');
import bar1 = require('foo');
import bas1 = require('foo');
const ensureImport: any =
    fo0o1
    && bar1
    && bas1;


// namespaces
namespace Utility {
  export function log () {}
}
// nested namespace
namespace Utility.msg {
  export function log () {}
}

Utility.log()
Utility.msg.log()


// inline type annotation
var name: {first: string; second: string}

// Generics
function reverse<T> (items: T[]): T[] {
  let t = []
  return t
}

// Union Type
function fc (command: string[] | string) {}
// intersection type
function extend<T, U> (first: T, sencond: U): T & U {
  return { ...first, ...sencond}
}
// Tuple type
let nn: [string, number]
nn = ['a', 111]

// type alias
type StrOrNum = string | number;
let sample: StrOrNum;
sample = 1
sample = "1"

type Text = string | { text: string }
type Callback = (data: string) => void;


// import jquery from 'jquery'


declare var xxxx: any;
xxxx = 33333

bob.ssss = 3333 // vendor.d.ts


process.exitWithLogging = function() {
  console.log("exiting");
  process.exit.apply(process, arguments);
};

process.exit = function () {
  process.exit()
}
process.exit()


// interfaces

interface Point {x: number; y: number}
declare var myPoint: Point;

interface Point {z: number}

myPoint.z // allowed

// enums
enum Colors {Red, Green, Blue}
let c1 = Colors.Blue
c1


// function 
function f1 (p: {bar: number}) {} // parameter annotations

//function overloading
function padding(all: number);
function padding(topAndBottom: number, leftAndRight: number);
function padding(top: number, right: number, bottom: number, left: number);
function padding(a: number, b?: number, c?: number, d?: number) {
  if (b === undefined && c === undefined && d === undefined) {
      b = c = d = a;
  }
  else if (c === undefined && d === undefined) {
      c = a;
      d = b;
  }
  return {
      top: a,
      right: b,
      bottom: c,
      left: d
  };
}

// declaring functions
type LongHand = {(a: number): number};
type ShortHand = (a: number) => number
// overloading
type LongHandAllowsOverloadDeclarations = {
  (a: number): number;
  (a: string): string;
}

interface ReturnString {
  (): string
}
declare const foo: ReturnString;
const b = foo();

interface Overloaded {
  (foo: string): string
  (foo: number): number
}

// example implementation
function stringOrNumber(foo: number): number;
function stringOrNumber(foo: string): string;
function stringOrNumber(foo: any): any {
  if (typeof foo === 'number') {
      return foo * foo;
  } else if (typeof foo === 'string') {
      return `hello ${foo}`;
  }
}

const overloaded: Overloaded = stringOrNumber;

// example usage
const str = overloaded(''); // type of `str` is inferred as `string`
const num = overloaded(123); // type of `num` is inferred as `number`



const overloaded1: {
  (foo: string): string
  (foo: number): number
} = (foo: any) => foo;


const simple: (foo: number) => string
    = (foo) => foo.toString();


interface CallMeWithNewToGetString {
  new (): string
}
// Usage
declare const Foo2: CallMeWithNewToGetString;
const bar = new Foo2(); // bar is inferred to be of type string    



// type assertion
interface Foo {
  bar2: number;
  bas2: string;
}
var foo2 = {} as Foo;
foo2.bar2 = 123;
foo2.bas2 = 'hello';



interface A {
  x: number;
}
interface B {
  y: string;
}

function doStuff(q: A | B) {
  if ('x' in q) {
    // q: A
  }
  else {
    // q: B
  }
}


type TriState = 'yes' | 'no' | 'unknown';

function logOutState(state:TriState) {
  if (state == 'yes') {
    console.log('User selected yes');
  } else if (state == 'no') {
    console.log('User selected no');
  } else {
    console.log('User has not made a selection yet');
  }
}


let ffoo: "Hello" // literal string
function iTakeFoo(foo: 'foo') { }
const test = {
  someProp: 'foo' as 'foo'
};
iTakeFoo(test.someProp); // Okay!


type Foo21 = {
  readonly bar: number;
  readonly bas: number;
}
class Fwoo {
  readonly bar = 1; // OK
  readonly baz: string;
  constructor() {
      this.baz = "hello"; // OK
  }
}
/*
const
  is for a variable reference
  the variable cannot be reassigned to anything else.
readonly is
  for a property
  the property can be modified because of aliasing
*/